package com.stu.spring.sim.circular;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 二级缓存
 */
public class SimCircular3Ctx {

    private Map<String, BeanDefinition> beanDefinitionMap = new LinkedHashMap<>();

    // 一级缓存，最终完整 bean 对象
    private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();

    private Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();

    private Map<String, ObjectFactory> factoriesObjects = new ConcurrentHashMap<>();

    public SimCircular3Ctx() throws Exception {
        // 加载 ioc 容器
        refresh();
    }

    private void refresh() throws Exception {
        // 读取 BeanDefinition
        loadBeanDefinitions();

        // 创建 bean
        finishBeanFactoryInitialization();
    }

    private void loadBeanDefinitions() {
        RootBeanDefinition beanDefinition1 = new RootBeanDefinition(AService.class);
        RootBeanDefinition beanDefinition2 = new RootBeanDefinition(BService.class);
        beanDefinitionMap.put("aService", beanDefinition1);
        beanDefinitionMap.put("bService", beanDefinition2);
    }

    private void finishBeanFactoryInitialization() throws Exception {
        for(String beanName : beanDefinitionMap.keySet()){
            getBean(beanName);
        }
    }

    // 方法如果加 synchronized 会有性能问题，因此有了二级缓存
    public Object getBean(String beanName) throws Exception {
        // 1 获取
        Object bean = getSingleton(beanName);
        if(Objects.nonNull(bean)){
            return bean;
        }
        synchronized (singletonObjects){
            bean = getSingleton(beanName);
            if(Objects.nonNull(bean)){
                return bean;
            }
        }
        // 2 创建
        // 2.1 实例化
        RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
        Class<?> beanClass = beanDefinition.getBeanClass();
        Object beanInstance = beanClass.getConstructor().newInstance();

        // put 到三级缓存
        // 预期只有循环依赖的 bean 才进行动态代理，普通的 bean 依然在初始化后才去创建动态代理
        factoriesObjects.put(beanName, () -> new JdkProxyBeanPostProcessor().getEarlyBeanReference(beanInstance, beanName));

        // 2.2 依赖注入 @Autowired
        for(Field declaredField : beanClass.getDeclaredFields()){
            if(declaredField.getAnnotation(Autowired.class) != null){
                String name = declaredField.getName();

                // bytype byname
                Object dependBean = getBean(name);

                declaredField.setAccessible(true);
                declaredField.set(beanInstance, dependBean);
            }
        }

        // 2.3 初始化 aop

        // 3 put 到一级缓存
        singletonObjects.put(beanName, beanInstance);
        earlySingletonObjects.remove(beanName);
        return beanInstance;
    }

    private Object getSingleton(String beanName) {
        if(singletonObjects.containsKey(beanName)){
            return singletonObjects.get(beanName);
        }
        // spring 源码锁的都是 singletonObjects
        synchronized (singletonObjects){
            if(earlySingletonObjects.containsKey(beanName)){
                return earlySingletonObjects.get(beanName);
            }
            if(factoriesObjects.containsKey(beanName)){
                ObjectFactory objectFactory = factoriesObjects.get(beanName);
                Object aopObject = objectFactory.getObject();
                // 存二级缓存，防止循环依赖多次
                earlySingletonObjects.put(beanName, aopObject);
                return aopObject;
            }
        }
        return null;
    }

}
